namespace Tekdev.CrystalReports
{
	using System;
	using System.IO;
	using CrystalDecisions.CrystalReports.Engine;
	using CrystalDecisions.Shared;

	public class Report : IDisposable
	{
		#region Public Properties
		private string _filePath;
		public string FilePath
		{
			get { return _filePath; }
			set { _filePath = value; }
		}

		private string _userID;
		public string UserID
		{
			get { return _userID; }
			set { _userID = value; }
		}

		private string _password;
		public string Password
		{
			get { return _password; }
			set { _password = value; }
		}

		private string _server;
		public string Server
		{
			get { return _server; }
			set { _server = value; }
		}

		private string _database;
		public string Database
		{
			get { return _database; }
			set { _database = value; }
		}

		private string[] _parameters;
		public string[] Parameters
		{
			get { return _parameters; }
			set { _parameters = value; }
		}

		private FileType _exportType;
		public FileType ExportType
		{
			get { return _exportType; }
			set { _exportType = value; }
		}
		#endregion

		#region Constructors
		public Report()
		{
		
		}

		public Report(string filePath) : this()
		{
			_filePath = filePath;
		}

		
		public Report(string filePath, string[] parameters) : this(filePath)
		{
			_parameters = parameters;
		}

		public Report(string filePath, string userID, string password, string server, string database) : this(filePath)
		{
			_userID = userID;
			_password = password;
			_server = server;
			_database = database;
		}

		public Report(string filePath, string userID, string password, string server, string database, params string[] parameters) : this(filePath, userID, password, server, database)
		{
			_parameters = parameters;
		}
		#endregion

		#region Methods
		public void SaveToDisk(string path)
		{			
			if(_filePath == null)
			{
				throw new MissingFieldException("FilePath property has not been set", "FilePath");
			}
			
			MemoryStream reportStream = (MemoryStream)GetStream(_filePath, _exportType, _userID, _password, _server, _database, _parameters);
			FileStream file = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None);
			file.Write(reportStream.ToArray(), 0, (int)reportStream.Length);
			file.Close();
			reportStream.Close();		
		}
		#endregion

		#region Static Methods
		public static Stream GetStream(string filePath)
		{
			return GetStream(filePath, FileType.PortableDocFormat, null, null, null, null, null);
		}
		
		public static Stream GetStream(string filePath, FileType type)
		{
			return GetStream(filePath, type, null, null, null, null, null);
		}

		public static Stream GetStream(string filePath, FileType type, string[] parameters)
		{
			return GetStream(filePath, type, null, null, null, null, parameters);
		}

		public static Stream GetStream(string filePath, FileType type, string userID, string password, string server, string database, params string[] parameters)
		{
			ReportDocument rep = new ReportDocument();
			TableLogOnInfo logon = new TableLogOnInfo();
			ConnectionInfo conn = new ConnectionInfo();			

			//If user set the database info
			if(userID != null && userID != string.Empty && 
				server != null && server != string.Empty && 
				database != null && database != string.Empty)
			{
				//Load the report into memory and connect to the database
				rep.Load(filePath);
				conn.UserID = userID;
				conn.Password = password;
				conn.ServerName = server;
				conn.DatabaseName = database;

				//Login to each section that needs a login
				foreach(CrystalDecisions.CrystalReports.Engine.Table table in rep.Database.Tables)
				{
					logon  = table.LogOnInfo;
					logon.ConnectionInfo = conn;
					table.ApplyLogOnInfo(logon);
				}
			}

			//If parameters are passed in
			if(parameters != null && parameters.Length > 0)
			{
				ParameterFieldDefinitions crParameterFieldDefinitions = rep.DataDefinition.ParameterFields;					

				int i = 0;
				foreach(string parameter in parameters)
				{				
					string tmpParam = parameter;
					if(tmpParam == String.Empty)
					{
						tmpParam = null;
					}

					ParameterFieldDefinition crParameterFieldDefinition = crParameterFieldDefinitions[i];
					ParameterValues crParameterValues = crParameterFieldDefinition.CurrentValues;
					if(crParameterFieldDefinition.IsLinked())
					{
						i++;
						continue;
					}

					ParameterDiscreteValue crParameterDiscreteValue = new ParameterDiscreteValue();
					crParameterDiscreteValue.Value = tmpParam;
					crParameterValues.Add(crParameterDiscreteValue);
					crParameterFieldDefinition.ApplyCurrentValues(crParameterValues);
				
					i++;
				}
			}

			CrystalDecisions.Shared.ExportFormatType formatType = CrystalDecisions.Shared.ExportFormatType.PortableDocFormat;

			switch(type)
			{
				case FileType.Excel:
					formatType = CrystalDecisions.Shared.ExportFormatType.Excel;
					break;
				case FileType.HTML_3_2:
					formatType = CrystalDecisions.Shared.ExportFormatType.HTML32;
					break;
				case FileType.HTML_4_0:
					formatType = CrystalDecisions.Shared.ExportFormatType.HTML40;
					break;
				case FileType.NoFormat:
					formatType = CrystalDecisions.Shared.ExportFormatType.NoFormat;
					break;
				case FileType.PortableDocFormat:
					formatType = CrystalDecisions.Shared.ExportFormatType.PortableDocFormat;
					break;
				case FileType.RichText:
					formatType = CrystalDecisions.Shared.ExportFormatType.RichText;
					break;
				case FileType.Word:
					formatType = CrystalDecisions.Shared.ExportFormatType.WordForWindows;
					break;
			}

			MemoryStream oStream = new MemoryStream();				
			oStream = (MemoryStream)rep.ExportToStream(formatType);

			rep.Dispose();
			logon = null;
			conn = null;
			return oStream;
		}
		#endregion

		#region IDisposable Members
		public void Dispose()
		{
			_filePath = null;
			_parameters = null;
			_userID = null;
			_password = null;
			_server = null;
			_database = null;			
		}
		#endregion
	}
}